package nsoft.timeline.util;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;

import org.tritonus.share.sampled.file.TAudioFileFormat;

import javazoom.spi.mpeg.sampled.convert.DecodedMpegAudioInputStream;


public class mp3info {
	String mp3file="";
	int sampleRate=0;
	int numChannels=0;
	int sampleMax=0;
	int sampleMin=0;
	
	int[][] samplesContainer;
	
	public mp3info(String mp3file){
		this.mp3file=mp3file;
	}
	
	public String createImage(int w, int h, String path) 
									throws Exception {
		byte[] buff=getRawData(this.mp3file);
		int[][] samplesContainer=getSampleArray(buff);
		
		double biggestSample=0;
        if (sampleMax > sampleMin) {
            biggestSample = sampleMax;
        } else {
            biggestSample = Math.abs(((double) sampleMin));
        }
        
        BufferedImage bufImg=new BufferedImage(
        				w, h, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g=bufImg.createGraphics();
        drawWaveform(g,w,h,samplesContainer[0],biggestSample);
        g.dispose();
        
        String imgFile=new File(this.mp3file).getName();
        String dumpImgFileName=imgFile.substring(
        				0,imgFile.lastIndexOf('.'))+"_thumb.png";
        String dumpImgFile=path+"/"+dumpImgFileName;
        ImageIO.write(bufImg, "png", new File(dumpImgFile));
        
        return dumpImgFile;
	}

	@SuppressWarnings("rawtypes")
	public String getAudioFormat(String splitter) 
								throws Exception {
		StringBuilder buff=new StringBuilder();
		File file = new File(this.mp3file);
		AudioFileFormat baseFileFormat=
				AudioSystem.getAudioFileFormat(file);
		
		if (baseFileFormat instanceof TAudioFileFormat){
		    Map mp3tag=
		    	((TAudioFileFormat)baseFileFormat).properties();
		    int kbps=getInt(mp3tag.get(
		    		"mp3.bitrate.nominal.bps"))/1000;
		    buff.append(mp3tag.get("title")).append(splitter)
		    	.append(mp3tag.get("author")).append(splitter)
		    	.append(mp3tag.get(
		    		"mp3.version.encoding")).append(splitter)
		    	.append(getChannels(mp3tag.get(
		    		"mp3.channels"))).append(splitter)
		    	.append(kbps).append("kbps").append(splitter)
		    	.append(mp3tag.get(
		    		"mp3.frequency.hz")).append("hz");
		}
		return buff.toString().trim();
	}
	
	private String getChannels(Object numChannels){
		int num=2;
		try{
			if (numChannels instanceof String)
				num=Integer.parseInt((String)numChannels);
		}catch(Exception ex){}
		return num==2?"stereo":"mono";
	}
	
	private int getInt(Object val){
		try{
			if (val instanceof String)
				return Integer.parseInt((String)val);
			else if (val instanceof Integer)
				return (Integer)val;
			else
				return 0;
		}catch(Exception ex){
			return 0;
		}
	}
	
    private void drawWaveform(Graphics2D g,int imgW, int imgH, 
    					int[] samples, double biggestSample){
        Color waveColor=new Color(112,146,190);
    	
    	if (samples==null){
            return;
        }

        int oldX = 0;
        int oldY = (int)(imgH/2);
        int xIndex = 0;
        int sampleLength=samples.length;

        int increment = getIncrement(
        		getXScaleFactor(imgW,sampleLength),sampleLength);
        g.setColor(waveColor);

        int t = 0;

        for (t = 0; t < increment; t += increment) {
            g.drawLine(oldX, oldY, xIndex, oldY);
            xIndex++;
            oldX = xIndex;
        }

        for (; t < samples.length; t += increment) {
            double scaleFactor=getYScaleFactor(imgH,biggestSample);
            double scaledSample = samples[t] * scaleFactor;
            int y = (int)((imgH/2)-(scaledSample));
            g.drawLine(oldX, oldY, xIndex, y);

            xIndex++;
            oldX = xIndex;
            oldY = y;
        }
    }
    
	private int[][] getSampleArray(byte[] rawdata){
        int[][] toReturn = new int[numChannels]
        				[rawdata.length / (2 * numChannels)];
        int index = 0;

        for (int t = 0; t < rawdata.length;){
            /** for each iteration, loop through the channels */
            for (int a = 0; a < numChannels; a++) {
                /** do the byte to sample conversion
                	see AmplitudeEditor for more info */
                int low = (int) rawdata[t];
                t++;
                int high = (int) rawdata[t];
                t++;
                int sample = (high << 8) + (low & 0x00ff);

                if (sample < sampleMin){
                    sampleMin = sample;
                } else if (sample > sampleMax) {
                    sampleMax = sample;
                }
                toReturn[a][index] = sample;
            }
            index++;
        }

        return toReturn;
	}
	
	/*
	private int getBitSample(int high, int low){
		return (high << 8) + (low & 0x00ff);
	}
	*/
	
	private byte[] getRawData(String mp3file) throws 
				UnsupportedAudioFileException, IOException, Exception {
		ByteArrayOutputStream f=new ByteArrayOutputStream();
		AudioInputStream in=null;
		DecodedMpegAudioInputStream decoder=null;
		try {
			in=AudioSystem.getAudioInputStream(new File(mp3file));
			AudioFormat baseformat=in.getFormat();

			numChannels=baseformat.getChannels();
			
			AudioFormat decodedFormat=new AudioFormat(
							AudioFormat.Encoding.PCM_SIGNED, 
							baseformat.getSampleRate(),16, 
							baseformat.getChannels(), 
							baseformat.getChannels()*2,
							baseformat.getSampleRate(), false);

			decoder= new DecodedMpegAudioInputStream(
									decodedFormat, in);

			byte[] byteData=new byte[4];
			int nBytesRead=0;
			int offset=0;
			
			while(nBytesRead != -1){
				nBytesRead=decoder.read(
						byteData, offset, byteData.length);
				
				if (nBytesRead != -1){
					int numShorts=nBytesRead >> 1;
					for (int j=0;j<numShorts;j++){
						f.write(byteData[j]);
					}
				}
			}
		}catch(Exception ex){
			throw ex;
		}finally{
			if (decoder!=null)
				decoder.close();

			if (in != null)
				in.close();
		}
		
		byte[] buff=new byte[f.size()];
		buff=f.toByteArray();
		f.close();
		
		return buff;
	}
	
    private int getIncrement(double xScale,int length){
        try {
            int increment=(int)(length/(length * xScale));
            return increment;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return -1;
    }

    private double getXScaleFactor(int imgW, int length){
        return (imgW/((double)length));
    }

    private double getYScaleFactor(int imgH, 
    						double biggestSample){
        return (imgH/(biggestSample*2*1.2));
    }
}
